package edu.jhu.cs.oose.scheduleit.vo;



import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;

import edu.jhu.cs.oose.scheduleit.util.DateWrapper;
import edu.jhu.cs.oose.scheduleit.util.EventType;

/**
 * Entity class of event
 * @author oose_group2
 *
 */
@Entity
public class Event implements Comparable<Event> {

	/**
	 * The identifier for each event
	 */
	@Id
	@GeneratedValue
	private int id;

	/**
	 * The schedule hosting this event
	 */
	@OneToOne
	private Schedule container;

	/**
	 * The user who creates this event
	 */
	@OneToOne
	private UserInfo author;

	/**
	 * The start time of this event
	 */
	@Temporal(TemporalType.TIMESTAMP)
	private Calendar startTime;

	/**
	 * The end time of this event
	 */
	@Temporal(TemporalType.TIMESTAMP)
	private Calendar endTime;

	/**
	 * Detailed information of this event
	 */
	@Basic
	private String description;

	/**
	 * The users who joined this event
	 */
	@ManyToMany(fetch = FetchType.EAGER)
	@GenericGenerator(name="uuid-gen", strategy = "uuid")
    @CollectionId(columns = @Column(name = "COL_ID"), type = @Type(type = "string"), generator = "uuid-gen") 
    private List<UserInfo> joinedUsers;

	/**
	 * The type of this event
	 */
	@Enumerated(EnumType.STRING)
	private EventType type;

	/**
	 * The getter for author
	 * @return
	 */
	public UserInfo getAuthor() {
		return author;
	}

	/**
	 * The setter for author
	 * @param author
	 */
	public void setAuthor(UserInfo author) {
		this.author = author;
	}

	/**
	 * The getter for container
	 * @return
	 */
	public Schedule getContainer() {
		return container;
	}

	/**
	 * The setter for container
	 * @param container
	 */
	public void setContainer(Schedule container) {
		this.container = container;
	}

	/**
	 * The getter for id
	 * @return
	 */
	public int getId() {
		return id;
	}

	/**
	 * The setter for id
	 * @param id
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * The getter for startTime
	 * @return
	 */
	public DateWrapper getStartTime() {
		return new DateWrapper(this.startTime);
	}

	/**
	 * The setter for startTime
	 * @param startTime
	 */
	public void setStartTime(DateWrapper startTime) {
		this.startTime = startTime.getTime();
	}

	/**
	 * The getter for endTime
	 * @return
	 */
	public DateWrapper getEndTime() {
		return new DateWrapper(this.endTime);
	}

	/**
	 * The setter for endTime
	 * @param endTime
	 */
	public void setEndTime(DateWrapper endTime) {
		this.endTime = endTime.getTime();
	}

	/**
	 * The getter for description
	 * @return
	 */
	public String getDescription() {
		return description != null? this.description:"";
	}

	/**
	 * The setter for description
	 * @param description
	 */
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * The getter for joinedUsers
	 * @return
	 */
	public List<UserInfo> getJoinedUsers() {
		if (this.joinedUsers == null){
			this.joinedUsers = new LinkedList<UserInfo>();
		}
		return joinedUsers;
	}

	
	/**
	 * Add a user joined this event
	 * @param user	The user who wants to join this event
	 * @return	Whether it's successful for this operation
	 */
	public boolean addUser(UserInfo user) {
		if (this.type == EventType.VIEW){
			return false;
		}
		if (this.joinedUsers == null){
			this.joinedUsers = new LinkedList<UserInfo>();
		}		
		return this.joinedUsers.contains(user)?true:this.joinedUsers.add(user);
	}


	/**
	 * Remove a user joined this event
	 * @param user	The user who joined this event and wants to dis-join it
	 * @return	Whether it's successful for this operation
	 */
	public boolean removeUser(UserInfo user) {
		if (this.type == EventType.VIEW){
			return false;
		}
		return this.joinedUsers == null? false:this.joinedUsers.remove(user);
	}

	/**
	 * Remove all of users who joined this event
	 */
	public void removeAllUsers(){
		if (this.joinedUsers != null){
			this.joinedUsers.clear();
		}
	}
	
	/**
	 * The getter for type
	 * @return
	 */
	public EventType getType() {
		return type;
	}

	/**
	 * The setter for type
	 * @param type
	 */
	public void setType(EventType type) {
		this.type = type;
	}

	@Override
	public int compareTo(Event event) {
		if (this.getId() == event.getId()) {
			return 0;
		} else if (this.getId() == 0) {
			return -1;
		} else if (event.getId() == 0) {
			return 1;
		} else {
			return this.getId() > event.getId() ? 1 : -1;
		}
	}
	
	/**
	 * Compare an object with this event
	 * @param obj	The object going to be compared
	 * @return	Whether the input object is equal to this event
	 */
	public boolean equals(Object obj) {
		if (obj instanceof Event) {
			return this.getId() == ((Event) obj).getId();
		}
		return false;
	}

}
